#ifndef _TRANSPORT_H
#define _TRANSPORT_H

#include "signature.h"

#include <sys/types.h>
#include <pthread.h>

#include <gloox/client.h>
#include <gloox/message.h>
#include <gloox/messagehandler.h>
#include <gloox/connectionlistener.h>

#include <string>
#include <vector>

class transport_listener {
public:
    virtual ~transport_listener() {}
    virtual void on_data(const std::string &src, const std::string &data) = 0;
    virtual void on_close() {};
};

class transport {
public:
    transport(const std::string &id);
    virtual ~transport();

    std::string id() const;

    virtual bool connect(const std::vector<std::string> &options) = 0;
    virtual bool ucast(const std::string &to, const std::string &data) = 0;
    virtual bool bcast(const std::string &data) = 0;
    virtual bool close() = 0;

    void add_listener(transport_listener *l);

protected:
    std::string id_;
    std::vector<transport_listener *> listeners_;

};

/**
 * A lite implementation of secured transport. It assumes that the current
 * host has already got the public keys of other peers. A better implementation
 * should incorporate ssl handshake in the connecting process.
 */ 
class stransport_lite : public transport, public transport_listener {
public:
    stransport_lite(transport *trans);
    ~stransport_lite();

    bool connect(const std::vector<std::string> &options);

    /**
     * Create the hash of the message, encrypt the hash with my private key, 
     * and send the encrypted hash to the remote peer along with my signed
     * certificate.
     */
    bool ucast(const std::string &to, const std::string &data);
    bool bcast(const std::string &data);
    bool close();

private:
    bool sign(const std::string &data, std::string *signed_data);
    void on_data(const std::string &src, const std::string &data);

    transport *trans_;
    security_manager *secure_;

};

class xmpp_transport : public transport, public gloox::MessageHandler,
        public gloox::ConnectionListener {
public:
    enum state_t {
        DISCONNECTED,
        CONNECTING,
        CONNECTED,
    };

    xmpp_transport(const std::string &id);
    ~xmpp_transport();

    bool connect(const std::vector<std::string> &options);
    bool ucast(const std::string &to, const std::string &data);
    bool bcast(const std::string &data);
    bool close();

    void receive();

protected:
    void handleMessage(const gloox::Message &stanza, gloox::MessageSession
            *session);
    void onConnect();
    bool onTLSConnect(const gloox::CertInfo &info);
    void onDisconnect(gloox::ConnectionError e);

private:
    state_t state_;
    gloox::Client *client_;

    pthread_t recv_th_;

    // not sure if we need this, maybe gloox is thread-safe already
    pthread_mutex_t sending_m_; 
    pthread_mutex_t connect_m_;

    pthread_cond_t connected_cv_;
};

#endif
